﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using HaSdkWrapper;

namespace HaSdkDemo
{
    public partial class FormMultiCam : Form
    {
        private List<HaCamera> _cameras = new List<HaCamera>();
        private HA_IOStateCb_t _ioCb;
        private HA_ReadTSerialCb_t _serialCb;
        private List<HA_DataReadCb_t> _dataReceivedCbs = new List<HA_DataReadCb_t>();


        public FormMultiCam()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            AddCam(textBoxIp.Text, 3);
            //AddCam("192.168.1.154", 4);

        }

        private void AddCam(string ip, int parm)
        {
            var ctrl = new CamControl();
            ctrl.Dock = DockStyle.Fill;

            SplitterPanel container = _cameras.Count == 0 ? splitContainer1.Panel1 : splitContainer1.Panel2;

            container.Controls.Add(ctrl);

            var cam = new HaCamera();
            cam.Ip = ip;
            cam.Port = 9527;
            cam.Tag = ctrl;


            cam.VehicleCaptured += CamOnVehicleCaptured;
            cam.ConnectStateChanged += CamOnConnectStateChanged;
            cam.SerialDataRead += CamOnSerialDataRead;
            cam.IoStateChanged += CamOnIoStateChanged;
            cam.OfflineVehicleCaptured += CamOnOfflineVehicleCaptured;
            

            cam.Connect(ctrl.pictureBoxLiveVideo.Handle);
            //ctrl.Tag = cam.Cam;

            //HA_DataReadCb_t cb = DataReceivedCb;
            //_dataReceivedCbs.Add(cb);
            //HaSdk.HA_RegDataReadCbEx(cam.Cam, cb, parm);

            //_ioCb = this.IoStateCallback;
            //HaSdk.HA_RegIOStateCb(cam.Cam, _ioCb, IntPtr.Zero);

            //_serialCb = this.SerialReadCallback;
            //HaSdk.HA_RegReadTSerialCb(_serialCb, 0);

            //要把camera引用保存起来，否则可能被gc回收了
            _cameras.Add(cam);
        }


        private void RemoveCamera(HaCamera cam)
        {
            cam.VehicleCaptured -= CamOnVehicleCaptured;
            cam.ConnectStateChanged -= CamOnConnectStateChanged;
            cam.SerialDataRead -= CamOnSerialDataRead;
            cam.IoStateChanged -= CamOnIoStateChanged;
            cam.OfflineVehicleCaptured -= CamOnOfflineVehicleCaptured;

            cam.DisConnect();
            splitContainer1.Panel1.Controls.Remove(cam.Tag as Control);

        }

        private void CamOnIoStateChanged(object sender, IoStateChangedEventArgs ioStateChangedEventArgs)
        {
            var msg = string.Format("IO状态发生变化: Index:{0} State:{1}", ioStateChangedEventArgs.Index,
                ioStateChangedEventArgs.State);
            Log(msg);
        }

        private void CamOnSerialDataRead(object sender, SerialDataEventArgs serialDataEventArgs)
        {
            var sb = new StringBuilder();
            foreach (var b in serialDataEventArgs.Data)
            {
                sb.AppendFormat("{0:x2} ", b);
            }

            var msg = string.Format("读取到串口数据： Index: {0} data: {1}", serialDataEventArgs.Index, sb);
            Log(msg);
        }

        private void CamOnConnectStateChanged(object sender, ConnectEventArgs connectEventArgs)
        {
            var cam = (HaCamera)sender;
            var msg = string.Format("{0} 是否连接: {1}", cam.Ip, connectEventArgs.Connected);
            Log(msg);
        }

        private void DataReceivedCb(IntPtr cam, string ip, ushort port, int dataType, IntPtr data, uint dataLen, int usrParam)
        {
            switch (dataType)
            {
                case HaSdkConstants.MESSAGE_ID_CAR:

                    var pkg = (pkg_vehicle)Marshal.PtrToStructure(data, typeof(pkg_vehicle));
                    CamControl ctrl = null;
                    foreach (Control control in this.splitContainer1.Controls)
                    {

                        if ((IntPtr)control.Controls[0].Tag == cam)
                        {
                            ctrl = (CamControl)control.Controls[0];
                            break;
                        }
                    }



                    if (ctrl != null && pkg.img_num > 0)
                    {
                        var ptr = pkg.img[0];
                        var len = pkg.img_len[0];
                        var mem = new byte[len];
                        Marshal.Copy(ptr, mem, 0, (int)len);
                        Action<CamControl, byte[]> ac = ShowImage;
                        this.BeginInvoke(ac, ctrl, mem);
                    }


                    break;
            }
        }

        private static void ShowImage(CamControl ctrl, byte[] mem)
        {

            var old = ctrl.pictureBoxCapture.Image;
            ctrl.pictureBoxCapture.Image = Image.FromStream(new MemoryStream(mem));
            if (old != null)
            {
                old.Dispose();
            }
        }

        private void CamOnOfflineVehicleCaptured(object sender, VehicleCapturedEventArgs vehicleCapturedEventArgs)
        {
            var cam = sender as HaCamera;
            var ctrl = (CamControl)cam.Tag;
            if (InvokeRequired)
            {
                Action<HaCamera, VehicleCapturedEventArgs> ac = ShowPlate;
                this.BeginInvoke(ac, cam, vehicleCapturedEventArgs);
            }
        }



        private void CamOnVehicleCaptured(object sender, VehicleCapturedEventArgs vehicleCapturedEventArgs)
        {
            var cam = sender as HaCamera;
            var ctrl = (CamControl)cam.Tag;
            if (InvokeRequired)
            {
                Action<HaCamera, VehicleCapturedEventArgs> ac = ShowPlate;
                this.BeginInvoke(ac, cam, vehicleCapturedEventArgs);
            }
        }

        private void CamOnImageDecoded(object sender, ImageDecodedEventArg imageDecodedEventArg)
        {
            var cam = sender as HaCamera;
            var ctrl = (CamControl)cam.Tag;

            if (InvokeRequired)
            {
                //Debug.WriteLine(cam.Ip);
                //var ac = new Action<PictureBox, Image>(ShowImage);
                //this.BeginInvoke(ac, ctrl.pic id == 0 ? pictureBoxRealTime1 : pictureBoxRealTime2, imageDecodedEventArg.Image);
            }



        }

        private void ShowPlate(HaCamera sender, VehicleCapturedEventArgs e)
        {
            var ctrl = (CamControl)sender.Tag;
            ctrl.labelIP.Text = sender.Ip;

            ctrl.labelLicenseNumber.Text = string.Format("{0} ({1}) @ {2:T} {3}",
                string.IsNullOrEmpty(e.License) ? "无牌" : e.License, 
                e.Color, 
                e.PlateTime,
                e.IsOffline ? "离线数据" : "");
            var img = ctrl.pictureBoxCapture.Image;
            var imgNew = Image.FromStream(new MemoryStream(e.JpegBuffer));
            ctrl.pictureBoxCapture.Image = imgNew;
            if (img != null)
            {
                img.Dispose();
            }

        }

        private void ShowImage(PictureBox pic, Image img)
        {
            var old = pic.Image;
            //如果要在以后使用图片，应该clone一份，因为回调结束后，image会被dispose
            pic.Image = (Image)img.Clone();
            if (old != null)
            {
                old.Dispose();
            }
        }

        private void buttonCaptureImage_Click(object sender, EventArgs e)
        {

            //try
            //{
            //    var ib = _cameras[0].CaptureImage();
            //    labelIP2.Text = string.Format("截图成功 @ {0} len: {1}", DateTime.Now, ib.Length);
            //    if (ib.Length > 0)
            //    {
            //        var old = pictureBoxCapture.Image;
            //        var newImage = Image.FromStream(new MemoryStream(ib));
            //        pictureBoxCapture.Image = newImage;
            //        if (old != null)
            //        {
            //            old.Dispose();
            //        }

            //    }
            //}
            //catch (Exception ex)
            //{

            //    labelIP2.Text = ex.Message;
            //}



        }

        private void buttonGetWhitelist_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var lst = _cameras[0].GetAllowLists();
            foreach (var haAllowList in lst)
            {
                var msg = string.Format("hphm: {0} enable: year {1} month {2} day{3} due: year {4} month {5} day {6}",
                    haAllowList.plate,
                    haAllowList.enable_year,
                    haAllowList.enable_month,
                    haAllowList.enable_day,
                    haAllowList.year,
                    haAllowList.month,
                    haAllowList.day);
                Log(msg);
            }
        }

        private void buttonAddWhitelist_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var item = new HA_AllowList();
            item.plate = "WJ琼93003";
            item.enable_year = 2016;
            item.enable_month = 6;
            item.enable_day = 20;
            item.year = 2018;
            item.day = 3;
            item.month = 3;

            var res = _cameras[0].AddWhiteList(item);
            var msg = string.Format("增加白名单结果:{0}", res);
            Log(msg);
        }

        private void buttonDeletePlate_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var plate = "川A12345";
            var res = _cameras[0].DeleteWhiteList(plate);
            var msg = string.Format("删除 {0} 结果:{1}", plate, res);
            Log(msg);
        }

        private void buttonSearchIP_Click(object sender, EventArgs e)
        {
            using (var form = new FormIPList())
            {
                form.ShowDialog(this);
            }
        }

        private void buttonSetConfig_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var cfg = _cameras[0].GetGatewayConfig();
            var name = cfg.addr.AddrName;

            cfg.addr.AddrName = textBoxOsd.Text;
            //cfg.addr.addr_name = name;
            var res = _cameras[0].SetGatewayConfig(cfg);
            Log(string.Format("设置osd结果：{0}", res));

           
        }

        private void buttonSetIOState_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            if (comboBoxIOIndex.SelectedItem == null) return;

            //if (string.IsNullOrEmpty(comboBoxIOIndex.SelectedItem?.ToString()))
            //{
            //    MessageBox.Show("选择一个io口");
            //    return;
            //}

            var index = int.Parse(comboBoxIOIndex.SelectedItem.ToString());
            var state = checkBoxIOState.Checked ? 1 : 0;

            var res = HaSdk.HA_SetIOState(_cameras[0].Cam, index, state);
            if (res != 0)
            {
                MessageBox.Show("设置io口失败, error: " + res);
            }
        }


        private void Log(string msg)
        {
            this.listViewLogs.Invoke(new Action<string>(s => this.listViewLogs.Items.Insert(0, s)), msg);
        }

        private void buttonSendSerialData_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }
            var hex = textBoxHexData.Text.Replace(" ", "");
            if (hex.Length % 2 != 0)
	        {
                MessageBox.Show("16进制数据格式不正确");
                return;
	        }

            var bytes = Utils.StringToByteArray(hex);
            _cameras[0].WriteSerialData(1, bytes);
            Log("发送成功");
        }


        

        private void buttonClearLog_Click(object sender, EventArgs e)
        {
            listViewLogs.Clear();
        }

        private void buttonReadUserData_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var data = _cameras[0].ReadUserData();
            Log(string.Format("读出：{0}", data));
        }

        private void buttonWriteUserData_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var data = Guid.NewGuid().ToString();
            _cameras[0].WriteUserData(data);
            var msg = string.Format("写用户数据 {0}", data);
            Log(msg);
        }

        private void buttonPlayAudio_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.wav");
            var bytes = File.ReadAllBytes(path);
            _cameras[0].PlayAudio(bytes);
        }

        private void buttonReadTime_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var dt = _cameras[0].GetDateTime();
            var msg = string.Format("读时间：" + dt.ToString("yyyy-MM-dd HH:mm:ss"));
            Log(msg);
        }

        private void buttonWriteTime_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var datetime = DateTime.Now;
            _cameras[0].SetDateTime(datetime);
            Log("写时间成功");
        }

        private void buttonStopLiveVideo_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }
            _cameras[0].StopLiveVideo();
        }

        private void buttonDisConnect_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            RemoveCamera(_cameras[0]);
            _cameras.Remove(_cameras[0]);
        }

        private void buttonQueryOfflineDataCountByTime_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var res = _cameras[0].QueryOfflineCountByTime(DateTime.Now.AddHours(-10), DateTime.Now);
            Log(string.Format("查询返回结果：{0}", res));
        }

        private void buttonTrigger_Click(object sender, EventArgs e)
        {
            if (_cameras.Count == 0)
            {
                MessageBox.Show("未连接相机");
                return;
            }

            var res = _cameras[0].Trigger();
            Log(string.Format("触发结果：{0}", res));
        }
    }
}
